{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "aBGOAdWNr5b_"
      },
      "source": [
        "##### Copyright 2019 Google LLC.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "form",
        "colab": {},
        "colab_type": "code",
        "id": "VimNT0D8r9iG"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "jE3Sfy2UsNFt"
      },
      "source": [
        "# Interpolation\n",
        "\u003ctable class=\"tfo-notebook-buttons\" align=\"left\"\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/graphics/blob/master/tensorflow_graphics/notebooks/interpolation.ipynb\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" /\u003eRun in Google Colab\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "  \u003ctd\u003e\n",
        "    \u003ca target=\"_blank\" href=\"https://github.com/tensorflow/graphics/blob/master/tensorflow_graphics/notebooks/interpolation.ipynb\"\u003e\u003cimg src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\" /\u003eView source on GitHub\u003c/a\u003e\n",
        "  \u003c/td\u003e\n",
        "\u003c/table\u003e"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "VoYX4CGGhKjl"
      },
      "source": [
        "Given a limited number of pre-defined points and associated values, interpolation allows to predict new data points within the range of the pre-defined points.\n",
        "\n",
        "In the example below, the left plot shows samples represented as blue dots. Assuming that these samples come from a smooth function, one has many options available to find plausible values *between* these dots. A first option is to build a piece-wise linear function which links any pair of neighbouring points with a line, as can be observed in the central plot. Another widely used option is to fit a polynomial to these samples. The right plot illustrates a cubic polynomial fitted to the samples.\n",
        "\n",
        "![](https://storage.googleapis.com/tensorflow-graphics/notebooks/interpolation/interpolations.png)\n",
        "\n",
        "This notebook illustrates how to use [Tensorflow Graphics](https://github.com/tensorflow/graphics) to perform [B-Spline](https://en.wikipedia.org/wiki/B-spline) and [Slerp](https://en.wikipedia.org/wiki/Slerp) interpolation.\n",
        "\n",
        "**Note**: The easiest way to use this tutorial is as a Colab notebook, which allows you to dive in with no setup.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "TcP7ZpfIsWPA"
      },
      "source": [
        "## Setup \u0026 Imports\n",
        "If Tensorflow Graphics is not installed on your system, the following cell can install the Tensorflow Graphics package for you."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "colab": {},
        "colab_type": "code",
        "id": "27WD490jsZOH"
      },
      "outputs": [],
      "source": [
        "!pip install tensorflow_graphics"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "HGynG-PLsdk9"
      },
      "source": [
        "Now that Tensorflow Graphics is installed, let's import everything needed to run the demo contained in this notebook."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "both",
        "colab": {},
        "colab_type": "code",
        "id": "odw6xhAGNYsX"
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import tensorflow as tf\n",
        "\n",
        "from tensorflow_graphics.math.interpolation import bspline\n",
        "from tensorflow_graphics.math.interpolation import slerp\n",
        "\n",
        "tf.compat.v1.enable_eager_execution()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "rqR_lelistPU"
      },
      "source": [
        "## Slerp interpolation\n",
        "Lerp is a widely used interpolation technique allowing to linearly interpolate between points. The piece-wise linear interpolation described at the beginning of this Colab effectively consists of pieces of linear interpolants. But what about if our data lives on a circle or at the surface of a sphere? In that case, Lerp would not provide a good way to interpolate, but fortunately, Slerp would! Slerp stands for *spherical* linear interpolation and has been introduced in the context of interpolating quaternions, which is a rotation formalism. We refer the interested reader to the [wikipedia page for Slerp](https://en.wikipedia.org/wiki/Slerp) for further details.\n",
        "\n",
        "The following demo allows to define two vectors, each starting from the center of a circle and ending on the circle. These define the vectors we want to interpolate between, and the slider 'percent' controls the extent to which each vector influences the interpolated vector. Note that the resulting vector also ends on the circle.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "form",
        "colab": {},
        "colab_type": "code",
        "id": "v9LPwqvGj8GG"
      },
      "outputs": [],
      "source": [
        "#@title Slerp - Vectors will be normalized first { vertical-output: true, run: \"auto\"}\n",
        "\n",
        "vector_1_x = -0.56  #@param { type: \"slider\", min: -1.0, max: 1.0, step: 0.01}\n",
        "vector_1_y = -0.39  #@param { type: \"slider\", min: -1.0, max: 1.0, step: 0.01}\n",
        "vector_2_x = 0.47  #@param { type: \"slider\", min: -1.0, max: 1.0, step: 0.01}\n",
        "vector_2_y = 0.74  #@param { type: \"slider\", min: -1.0, max: 1.0, step: 0.01}\n",
        "percent = 0.7  #@param { type: \"slider\", min: 0.0, max: 1.0, step: 0.01}\n",
        "\n",
        "vector_1 = tf.constant((vector_1_x, vector_1_y), dtype=tf.float32)\n",
        "vector_2 = tf.constant((vector_2_x, vector_2_y), dtype=tf.float32)\n",
        "vector_1 = tf.nn.l2_normalize(vector_1)\n",
        "vector_2 = tf.nn.l2_normalize(vector_2)\n",
        "vector_3 = slerp.interpolate(\n",
        "    vector_1, vector_2, percent, method=slerp.InterpolationType.VECTOR)\n",
        "\n",
        "v1 = vector_1.numpy()\n",
        "v2 = vector_2.numpy()\n",
        "v3 = vector_3.numpy()\n",
        "\n",
        "plt.figure(figsize=(10, 10))\n",
        "circle = plt.Circle((0, 0), 1.0, color='g', fill=False)\n",
        "ax = plt.gca()\n",
        "ax.add_artist(circle)\n",
        "plt.arrow(\n",
        "    0.0, 0.0, v1[0], v1[1], width=0.001, color='k', length_includes_head=True)\n",
        "plt.arrow(\n",
        "    0.0, 0.0, v2[0], v2[1], width=0.001, color='b', length_includes_head=True)\n",
        "plt.arrow(\n",
        "    0.0, 0.0, v3[0], v3[1], width=0.001, color='r', length_includes_head=True)\n",
        "plt.axis((-1.1, 1.1, -1.1, 1.1))\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "0Ws-pxYVsp2Q"
      },
      "source": [
        "## B-Spline interpolation\n",
        "As opposed to other interpolation techniques that have a global support (e.g. bezier curve, global polynomial fit), B-Spline are piece-wise polynomial functions that provide local control. The control comes from the position of points called 'knots'. The following demo illustrates how the position of these knots *locally* affect the interpolated curve.\n",
        "\n",
        "We refer the interested reader to the [wikipedia page for B-Spline](https://en.wikipedia.org/wiki/B-spline) for further details."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 0,
      "metadata": {
        "cellView": "form",
        "colab": {},
        "colab_type": "code",
        "id": "NOIF78eAOg-L"
      },
      "outputs": [],
      "source": [
        "#@title B-Spline Interpolation { vertical-output: true, run: \"auto\"}\n",
        "\n",
        "num_knots = 5\n",
        "cyclical = True  #@param { type: \"boolean\" }\n",
        "degree = 3  #@param { type: \"slider\", min: 1, max: 4, step: 1}\n",
        "knot_1_x = -2.5  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "knot_1_y = -1  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "knot_2_x = -1.5  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "knot_2_y = 2  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "knot_3_x = 0  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "knot_3_y = -3  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "knot_4_x = 1.5  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "knot_4_y = 3  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "knot_5_x = 3  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "knot_5_y = 0  #@param { type: \"slider\", min: -3.0, max: 3.0, step: 0.5}\n",
        "\n",
        "max_pos = num_knots if cyclical else num_knots - degree\n",
        "knots = tf.constant(((knot_1_x, knot_2_x, knot_3_x, knot_4_x, knot_5_x),\n",
        "                     (knot_1_y, knot_2_y, knot_3_y, knot_4_y, knot_5_y)))\n",
        "\n",
        "positions = tf.expand_dims(\n",
        "    tf.range(start=0.0, limit=max_pos, delta=0.01, dtype=knots.dtype), axis=-1)\n",
        "\n",
        "spline = bspline.interpolate(knots, positions, degree, cyclical)\n",
        "spline = tf.squeeze(spline, axis=1)\n",
        "\n",
        "plt.figure(figsize=(10, 10))\n",
        "plt.plot(spline[:, 0], spline[:, 1], 'r')\n",
        "plt.plot(knots[0, :], knots[1, :], 'b.')\n",
        "plt.axis((-3.5, 3.5, -3.5, 3.5))\n",
        "plt.show()"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "last_runtime": {
        "build_target": "//learning/brain/python/client:colab_notebook",
        "kind": "private"
      },
      "name": "interpolation.ipynb",
      "provenance": [],
      "toc_visible": true,
      "version": "0.3.2"
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
